﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Aribaccio.Security
{
    [ComVisible(true)]
    [ComSourceInterfaces(typeof(ISecurity))]
    [ClassInterface(ClassInterfaceType.AutoDispatch)]
    public class SecurityRC2 : ISecurity
    {
        /// <summary>
        /// 默认安全密钥，密钥必须为5-16位[安全密钥-加解密钥1]
        /// </summary>
        protected string DefaultSecretKey = "SECRET-CRYPTO-K1";
        /// <summary>
        /// 用于对称算法的初始化向量
        /// </summary>
        protected byte[] DefaultRgbIV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
        /// <summary>
        /// 默认安全密钥，密钥必须为5-16位
        /// </summary>
        public string SecretKey { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        public SecurityRC2()
        {
            this.SecretKey = string.Empty;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="argSecretKey">安全密钥，密钥必须为5-16位</param>
        public SecurityRC2(string argSecretKey)
        {
            this.SecretKey = argSecretKey;
        }

        /// <summary>
        /// RC2 加密(用变长密钥对大量数据进行加密)
        /// </summary>
        /// <param name="argEncryptString">待加密密文</param>
        /// <returns>returns</returns>
        public string Encrypt(string argEncryptString)
        {
            //检查，密文不得为空
            if (string.IsNullOrWhiteSpace(argEncryptString)) { return string.Empty; }
            //检查，密钥必须为5-16位
            if (string.IsNullOrWhiteSpace(this.SecretKey)) { this.SecretKey = DefaultSecretKey; }
            if (this.SecretKey.Length < 5 || this.SecretKey.Length > 16) { return string.Empty; }
          
            string resultEncrypt = "";
            RC2 rc2Provider = RC2.Create();
            try
            {
                byte[] encryptBytes = Encoding.Default.GetBytes(argEncryptString);
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, rc2Provider.CreateEncryptor(Encoding.Default.GetBytes(this.SecretKey), DefaultRgbIV), CryptoStreamMode.Write);
                cStream.Write(encryptBytes, 0, encryptBytes.Length);
                cStream.FlushFinalBlock();
                resultEncrypt = Convert.ToBase64String(mStream.ToArray());
                mStream.Close(); mStream.Dispose();
                cStream.Close(); cStream.Dispose();
            }
            catch (IOException) { resultEncrypt = string.Empty; }
            catch (CryptographicException) { resultEncrypt = string.Empty; }
            catch (ArgumentException) { resultEncrypt = string.Empty; }
            catch (Exception) { resultEncrypt = string.Empty; }
            finally { rc2Provider.Clear(); }
            return resultEncrypt;
        }

        /// <summary>
        /// RC2 解密(用变长密钥对大量数据进行加密)
        /// </summary>
        /// <param name="argDecryptString">待解密密文</param>
        /// <returns>returns</returns>
        public string Decrypt(string argDecryptString)
        {
            //检查，密文不得为空
            if (string.IsNullOrWhiteSpace(argDecryptString)) { return string.Empty; }
            //检查，密钥必须为5-16位
            if (string.IsNullOrWhiteSpace(this.SecretKey)) { this.SecretKey = DefaultSecretKey; }
            if (this.SecretKey.Length < 5 || this.SecretKey.Length > 16) { return string.Empty; }
           
            string resultDecrypt = "";
            RC2 rc2Provider = RC2.Create();
            try
            {
                byte[] decryptBytes = Convert.FromBase64String(argDecryptString);
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, rc2Provider.CreateDecryptor(Encoding.Default.GetBytes(this.SecretKey), DefaultRgbIV), CryptoStreamMode.Write);
                cStream.Write(decryptBytes, 0, decryptBytes.Length);
                cStream.FlushFinalBlock();
                resultDecrypt = Encoding.Default.GetString(mStream.ToArray());
                mStream.Close(); mStream.Dispose();
                cStream.Close(); cStream.Dispose();
            }
            catch (IOException) { resultDecrypt = string.Empty; }
            catch (CryptographicException) { resultDecrypt = string.Empty; }
            catch (ArgumentException) { resultDecrypt = string.Empty; }
            catch (Exception) { resultDecrypt = string.Empty; }
            finally { rc2Provider.Clear(); }
            return resultDecrypt;
        }
    }
}
